fix: Login page not accessible after disabling plugin.#94
Open
navidabdi wants to merge 4 commits into
Open
Conversation
On activation the plugin writes a .htaccess block that blocks direct access to /wp-login.php with 403 and rewrites /login.php to it. The deactivation hook never removed those rules, so deactivating the plugin left the site unable to reach the login page at all. Schema::deactivate() now removes every core-standards:* block the plugin previously added to the root and uploads .htaccess files (including the legacy core-standards:security marker), via a new marker-based removeBlockFromFile() helper.
Stands up the first automated test coverage for this plugin and locks in the deactivation/login fix from this PR as a regression test. Stack: - @wordpress/env boots a Dockerized WP + Apache + MariaDB sandbox so the plugin's .htaccess rules execute exactly as in production. - Playwright drives the tests; HTTP-only assertions use request context (no browser launch needed, fast in CI). - GitHub Actions workflow runs the suite on pull_request and pushes to master, uploading the Playwright report on failure. Files: - .wp-env.json (ports 8989/8990 to avoid colliding with other local wp-env instances) - playwright.config.js - tests/e2e/deactivation-restores-login.spec.js (7 test cases covering active state, deactivation cleanup, reactivation, and the legacy core-standards:security marker addressed by 95aefe6) - tests/e2e/helpers/wp-env.js (shared primitives for future specs) - tests/e2e/fixtures/legacy-security-block.htaccess - tests/e2e/README.md (contributor docs) - .github/workflows/e2e.yml - package.json: env:start / env:stop / env:clean / test:e2e scripts and devDependencies Verified locally: all 7 tests pass with the fix in place, and test 4 ("after deactivation: /wp-login.php is reachable again") fails when the fix is temporarily reverted, proving the suite guards the fix.
…t dir. When wp-env's `plugins: ["."]` is used, the activation slug is derived from the host directory's basename. On GitHub Actions the repo is checked out into `wordpress-core-standards/`, so the plugin slug became `wordpress-core-standards` and the hardcoded `wp plugin activate core-standards` in the test helper failed. Switching to `mappings` lets us control the destination path inside the container, so the slug is always `core-standards` regardless of where the repo lives on the host. Activation is handled by the test's beforeAll (it already was), so no behavior change locally.
sun
requested changes
May 18, 2026
sun
left a comment
Member
There was a problem hiding this comment.
Most of these rules are crucial for security and stability of the (production) site, we can’t remove them.
We can consider to hook their removal into wp plugin uninstall.
For the deactivate hook, I would suggest to only comment out the line that rejects access to the regular login front controller. Re-enabling the plugin will revert the change.
…n deactivate. The security/stability rules the plugin writes to .htaccess are needed in production even while the plugin is temporarily deactivated. Removing them on every deactivation was too aggressive (per PR review). New behavior: - deactivate(): comments out only the line that blocks /wp-login.php, so the login page is reachable while the plugin is inactive. All other rules (xmlrpc, .git, wp-includes/*.php, security headers, fast 404, uploads no-exec) remain in effect. Re-activation rewrites the security-files block from the template, restoring the line. - uninstall(): now performs the full .htaccess cleanup of every core-standards:* block (including the legacy core-standards:security marker) — fires via register_uninstall_hook when the plugin is permanently removed. Also fixed a regex bug in removeBlockFromFile: the previous `\b` after `core-standards:security` was satisfied by a hyphen, so removing the legacy marker could also strip `:security-files` / `:security-headers`. The marker is now anchored at end-of-line. E2E suite updated accordingly: - "after deactivation" tests now assert the security blocks REMAIN and only the wp-login.php rule line is commented out. - A new "uninstall" test invokes `wp plugin uninstall --skip-delete` to fire the uninstall hook (skip-delete keeps the bind-mounted plugin files intact) and verifies every block, including the legacy marker, is removed.
sun
approved these changes
Jul 6, 2026
Comment on lines
+58
to
+63
| // The plugin may be deactivated temporarily; the production security | ||
| // and stability rules in .htaccess must stay in place. Only the rule | ||
| // that blocks direct access to /wp-login.php is disabled, so the | ||
| // login page remains reachable while the plugin is inactive. | ||
| // Re-activation rewrites the security-files block from the template | ||
| // and naturally restores the line. |
Member
There was a problem hiding this comment.
Suggested change
| // The plugin may be deactivated temporarily; the production security | |
| // and stability rules in .htaccess must stay in place. Only the rule | |
| // that blocks direct access to /wp-login.php is disabled, so the | |
| // login page remains reachable while the plugin is inactive. | |
| // Re-activation rewrites the security-files block from the template | |
| // and naturally restores the line. | |
| // When temporarily disabling the plugin, disable the rule that | |
| // blocks direct access to /wp-login.php, so admins can log in. | |
| // Reenabling the plugin rewrites all templates, so the line is | |
| // restored. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
core-standardspreviously left a.htaccessblock in place that returned 403 Forbidden for/wp-login.phpand rewrote/login.phpto it, so the login page was unreachable until the plugin was reactivated or the rules were manually removed.Schema::deactivate()now removes everycore-standards:*block the plugin previously wrote to the root and uploads.htaccess(including the legacycore-standards:securitymarker addressed by 95aefe6), restoring the site to its pre-plugin state.removeBlockFromFile()helper so removal works regardless of what content an older plugin version may have written between the# BEGIN/# ENDmarkers.Test plan
grep -c "core-standards:" .htaccessreturns 5 and/login.phpworks while/wp-login.phpreturns 403.grep -c "core-standards:" .htaccessreturns 0, uploads.htaccessalso has 0 matches, and/wp-login.phploads the login form (no 403)./login.phpworks again.# BEGIN core-standards:security ... # END core-standards:securityblock manually, then deactivate — both legacy and current blocks should be removed..htaccessis missing or already clean — no errors, no file written.